package org.example.controller;

import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.util.CollectionUtil;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.FileUtils;
import org.example.bus.bean.RejectTask;
import org.example.bus.bean.WorkFlow;
import org.example.bus.bean.WorkFlowNode;
import org.example.enums.FlowNodeType;
import org.example.utils.ActivitiUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
public class ProcessController2 {
    @Autowired
    private RepositoryService repositoryService;  //流程定义和流程部署相关功能
    @Autowired
    private ProcessEngine processEngine;  //流程引擎

    @Resource
    TaskService taskService;


    @Autowired
    private ManagementService managementService;

    /**
     * 动态流程实例并输出png和xml
     *
     * @throws IOException
     */
    @GetMapping("/wf2/deploy")
    public String createDeployment()  {

        //模拟前端页面数据
        WorkFlow workFlow = new WorkFlow( "流程测试");
        WorkFlowNode s1 = new WorkFlowNode("start", FlowNodeType.START.getCode(),"zhangsan",null,null);
        s1.addNextNodeName("pgw-START");
        WorkFlowNode s2 = new WorkFlowNode("pgw-START", FlowNodeType.PGWS.getCode(), null, null, null);
        s2.addNextNodeName("task1").addNextNodeName("task21");
        WorkFlowNode s3 = new WorkFlowNode("task1", FlowNodeType.UTASK.getCode(), "wangwu", null, null);
        s3.addNextNodeName("pgw-END");

        WorkFlowNode s4 = new WorkFlowNode( "task21", FlowNodeType.UTASK.getCode(),"zhaoliu", null, null);
        s4.addNextNodeName("task22");

        WorkFlowNode s5 = new WorkFlowNode("task22",FlowNodeType.UTASK.getCode(), "zhuqi", null, null);
        s5.addNextNodeName("pgw-END");
        WorkFlowNode s6 = new WorkFlowNode( "pgw-END", FlowNodeType.PGWE.getCode(),null, null, null);
        s6.addNextNodeName("EGW");

        WorkFlowNode s7 = new WorkFlowNode( "EGW", FlowNodeType.EGW.getCode(),null, null, null);
        s7.addNextNodeName("task31").addNextNodeName("task32");
        WorkFlowNode s8 = new WorkFlowNode( "task31",FlowNodeType.UTASK.getCode(),"lisi", "flag == true", null);
        s8.addNextNodeName("receiveTask");
        WorkFlowNode s9 = new WorkFlowNode( "task32", FlowNodeType.UTASK.getCode(),"tianba", "flag == false", null);
        s9.addNextNodeName("receiveTask");
        WorkFlowNode s10 = new WorkFlowNode("receiveTask", FlowNodeType.RECEIVE.getCode(),"qianshi", null, null);
        s10.addNextNodeName("end");
        WorkFlowNode s11 = new WorkFlowNode("end", FlowNodeType.END.getCode(), null,null, null);


        List<WorkFlowNode> stepList = new ArrayList<>();
        stepList.add(s1);
        stepList.add(s2);
        stepList.add(s3);
        stepList.add(s4);
        stepList.add(s5);
        stepList.add(s6);
        stepList.add(s7);
        stepList.add(s8);
        stepList.add(s9);
        stepList.add(s10);
        stepList.add(s11);
        workFlow.setNodeList(stepList);

//        //创建ProcessEngine对象
//        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//        //得到RepositoryService
//        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 1. 建立模型
        BpmnModel model = new BpmnModel();
        Process process = new Process();
        model.addProcess(process);
        process.setId(workFlow.getName());
        process.setName(workFlow.getName());
        stepList.forEach(step -> {
            if (step.getType() == FlowNodeType.START.getCode()) {
                process.addFlowElement(ActivitiUtil.createStartEvent());
            } else if (step.getType() == FlowNodeType.END.getCode()) {
                process.addFlowElement(ActivitiUtil.createEndEvent());
            } else if (step.getType() == FlowNodeType.PGWS.getCode() || step.getType() == FlowNodeType.PGWE.getCode()) {
                process.addFlowElement(ActivitiUtil.createParallelGateway(step.getName(), step.getName()));
            } else if (step.getType() == FlowNodeType.EGW.getCode()) {
                process.addFlowElement(ActivitiUtil.createExclusiveGateway(step.getName(), step.getName()));
            } else if (step.getType() == FlowNodeType.RECEIVE.getCode()) {
                process.addFlowElement(ActivitiUtil.createReceiveTask(step.getName(), step.getName()));
            } else {
                process.addFlowElement(ActivitiUtil.createUserTask(step.getName(), step.getName(), step.getAssignee()));
            }
        });

        //连线
        Map<String,WorkFlowNode> nodeMap = workFlow.getNodeList().stream().collect(Collectors.toMap(WorkFlowNode::getName,node->node));

        nodeMap.forEach(
                (k,v)->{
                    List<String> nextNodesName = v.getNextNodesName();
                    if(CollectionUtil.isNotEmpty(nextNodesName)){
                        for(String nodeName:nextNodesName){
                            WorkFlowNode nextNode =nodeMap.get(nodeName);
                            //排他网关发起的节点才有条件
                            if (v.getType() == FlowNodeType.EGW.getCode()) {
                                process.addFlowElement(ActivitiUtil.createSequenceFlow(v.getName(), nextNode.getName(), nextNode.getEntryCondition()));
                            } else {
                                process.addFlowElement(ActivitiUtil.createSequenceFlow(v.getName(), nextNode.getName(), null));
                            }
                        }
                    }
                }
        );
        //deploy
        Deployment deployment = repositoryService.createDeployment().addBpmnModel("process/dynamic-model3.bpmn", model).name(workFlow.getName()).deploy();
        System.out.println("deploymentId:"+deployment.getId());
        return deployment.getId();
    }

    @GetMapping("/wf2/startTask/{workFlowName}")
    public String startTask(@PathVariable String workFlowName) throws IOException{
        //定义并设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("flag", 1 == 1);
//        //创建ProcessEngine对象
//        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//
//        //得到RepositoryService
//        RepositoryService repositoryService = processEngine.getRepositoryService();
        //start
        ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey(workFlowName, variables);
        System.out.println("processInstanceId:" + processInstance.getId());
        System.out.println("getProcessDefinitionId:"+processInstance.getProcessDefinitionId());

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        //save as  png
        new BpmnAutoLayout(bpmnModel).execute();
        List<String> highLightedActivities = processEngine.getRuntimeService().getActiveActivityIds(processInstance.getId());// 高亮节点
        List<String> highLightedFlows = new ArrayList<>(); // 高亮连接线
        ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivities, highLightedFlows, "宋体", "宋体", "宋体", null, 1.0);
        FileUtils.copyInputStreamToFile(inputStream, new File("E:\\process33.png"));

        Deployment deployment =repositoryService.createDeploymentQuery().deploymentName(workFlowName).singleResult();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        processDefinitionQuery.deploymentId(deployment.getId());
        ProcessDefinition processDefinition = processDefinitionQuery.singleResult();

        //save sa  xml
        InputStream inputStreamXml = processEngine.getRepositoryService().getResourceAsStream(deployment.getId(), processDefinition.getResourceName());
        FileUtils.copyInputStreamToFile(inputStreamXml, new File("E:\\process3.bpmn.xml"));
        return processInstance.getId();
    }

    //查看指定用户任务列表
    @GetMapping(value = "/wf2/taskList/{usrId}")
    public List<Map<String, Object>> taskList(@PathVariable String usrId) {
        Authentication.setAuthenticatedUserId(usrId);
        //mjm 为流程定义中分配的人员 对应 processes/SimpleProcess.bpmn:5
        List<org.activiti.engine.task.Task>  taskList = taskService.createTaskQuery().taskCandidateOrAssigned(usrId).list();
        return taskList.stream().map(task -> {
            Map<String, Object> data = new HashMap<>();
          //  data = BeanUtil.copyProperties(task, Map.class, "execution", "processInstance", "variableInstances");
            return data;
        }).collect(Collectors.toList());
    }

    //完成任务
    @GetMapping(value = "/wf2/completeTask/{usrId}/{processId}")
    public String completeTask(@PathVariable String usrId,@PathVariable String processId) {
        Authentication.setAuthenticatedUserId(usrId);
//        Authentication.setAuthenticatedUserId("王五");
        List<org.activiti.engine.task.Task> taskList = taskService.createTaskQuery().taskCandidateOrAssigned(usrId).processInstanceId(processId).list();
        if (CollectionUtil.isEmpty(taskList)) {
            throw new ActivitiObjectNotFoundException("processId:" + processId + " not found");
        }
        taskService.complete(taskList.get(0).getId());
        //mjm 为流程定义中分配的人员 对应 processes/SimpleProcess.bpmn:5
        return "操作完成!";
    }

    @GetMapping(value = "/wf2/rejectTask/{usrId}/{processId}")
    public String rejectTask(@PathVariable String usrId,String processId) {
        Authentication.setAuthenticatedUserId(usrId);
//        Authentication.setAuthenticatedUserId("王五");
        List<org.activiti.engine.task.Task> taskList = taskService.createTaskQuery().taskCandidateOrAssigned(usrId).processInstanceId(processId).list();
        if (CollectionUtil.isEmpty(taskList)) {
            throw new ActivitiObjectNotFoundException("processId:" + processId + "-Assignee:admin");
        }
        managementService.executeCommand(new RejectTask(taskList.get(0).getId(),new HashMap<>(),"驳回"));
        return "操作完成!";
    }
}